全面解读 angular 的 $q 机制

@license AngularJS v1.4.8

该代码块基于源码进行了删减
该代码块仅用于学习 分享 交流
为了代码的清晰,修改了部分非核心代码,并且删除了所有的异常处理
以下为 angular $q 的核心代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
var $q = {};
var defer = function() { return new Deferred(); };

function Promise() {
// 一共四种状态:
// 0: 等待
// 1: 通过
// 2: 拒绝
// -1: 处理 promise 对象
this.$$state = { status: 0 };
}

extend(Promise.prototype, {
// then 函数主要功能是 新创建 deferred 对象 并 往队列里面添加 回调函数
then: function(onFulfilled, onRejected, progressBack) {
// 没有任何回调直接返回
if (!onFulfilled && !onRejected && !progressBack) return this;
// 每执行一次 then 都会创建一个新的 Deferred 对象
var result = new Deferred();
this.$$state.pending = this.$$state.pending || [];
// 往队列里面添加 回调函数
this.$$state.pending.push([
result,
onFulfilled,
onRejected,
progressBack
]);
// 如果先执行了 状态方法 resolve 或 reject 再执行 then 时会直接执行对应的回调函数
// 即异步变成了同步 依然不影响程序的正常执行
if (this.$$state.status > 0) scheduleProcessQueue(this.$$state);
// 最后返回 Promise 对象 实现链式编程
return result.promise;
},
"catch": function(callback) {
// 相当于直接 reject 的回调 返回一个 promise 对象
return this.then(null, callback);
},
"finally": function(callback, progressBack) {
// 通过与拒绝都会执行 返回一个 promise 对象
return this.then(function(value) {
return handleCallback(value, true, callback);
}, function(error) {
return handleCallback(error, false, callback);
}, progressBack);
}
});
// 绑定上下文
function simpleBind(context, fn) {
return function(value) {
fn.call(context, value);
};
}

// $q 最核心的方法
// processQueue 用于执行回调函数
function processQueue(state) {
var fn, deferred, pending;
pending = state.pending;
state.processScheduled = false;
// 执行完毕之后 置空 队列里的所有回调函数
state.pending = undefined;
for (var i = 0, ii = pending.length; i < ii; ++i) {
deferred = pending[i][0];
// 巧妙的运用状态来控制回调函数
fn = pending[i][state.status];
if (isFunction(fn)) {
// fn(state.value) 回调函数
// 同时把回调函数的返回值传给 deferred.resolve()
// 这样就可以实现返回值的链式传递 .then().then().then()
// 第一个 then 是 最外层的 deferred 对象的 promise 对象的方法
// 第二个 then 是 在第一个 then 内部重新创建的 deferred 的 promise 对象的方法 每个 then 都会返回一个 result.promise 对象
// 也就是每执行调一次 then 方法就会嵌套一层 deferred 对象 (这个应该不是实现 promise 的最优解)
// 前面 pending 已经置空了 就保证了 在 执行 deferred.resolve 时 只会把回调函数的返回值传过去而不会继续执行
deferred.resolve(fn(state.value));
} else if (state.status === 1) {
deferred.resolve(state.value);
} else {
deferred.reject(state.value);
}
}
}

// 节流函数 阻止后续执行
function scheduleProcessQueue(state) {
if (state.processScheduled || !state.pending) return;
state.processScheduled = true;
processQueue(state);
}
// Deferred 构造函数
function Deferred() {
this.promise = new Promise();
this.resolve = simpleBind(this, this.resolve); // 实际上是调用的 原型的方法
this.reject = simpleBind(this, this.reject);
this.notify = simpleBind(this, this.notify);
}

extend(Deferred.prototype, {
// 节流函数 有状态直接返回
resolve: function(val) {
if (this.promise.$$state.status) return;
this.$$resolve(val);
},
// $$resolve 主要用于 改变状态 并 触发回调函数
$$resolve: function(val) {
var then, fns;
// callOnce 绑定this 返回 [this.$$resolve, this.$$reject]
// 这步操作应该放到下面
fns = callOnce(this, this.$$resolve, this.$$reject);
// 如果传过来的对象是 promise 对象
// 则把状态变为 -1 同时 执行 promise.then 并且 传递 this.$$resolve, this.$$reject 回调
// 这样就保证了对 传过来的 promise 对象的执行监听 同时也兼容了 原生 promise 对象
if ((isObject(val) || isFunction(val))) then = val && val.then;
if (isFunction(then)) {
this.promise.$$state.status = -1;
then.call(val, fns[0], fns[1], this.notify);
} else {
// 常规执行: 存储 val 值 更新状态 并 执行回调函数
this.promise.$$state.value = val;
this.promise.$$state.status = 1;
scheduleProcessQueue(this.promise.$$state);
}
},
reject: function(reason) {
if (this.promise.$$state.status) return;
this.$$reject(reason);
},
// 同 $$resolve 常规执行
$$reject: function(reason) {
this.promise.$$state.value = reason;
this.promise.$$state.status = 2;
scheduleProcessQueue(this.promise.$$state);
},
notify: function(progress) {
var callbacks = this.promise.$$state.pending;
if (
(this.promise.$$state.status <= 0) &&
callbacks &&
callbacks.length
) {
var callback, result;
for (var i = 0, ii = callbacks.length; i < ii; i++) {
result = callbacks[i][0];
// 执行传递给 then 的第三个回调函数 并把值传递给该回调
callback = callbacks[i][3];
result.notify(
isFunction(callback) ?
callback(progress) :
progress
);
}
}
}
});

// 对外的静态方法 用于 拒绝 promise 的执行
// 当在一个 promise 通过时 返回一个 reject(...) 则会继续拒绝通过
// 下面这个例子中 第二个then 的回调函数不会执行 直接走到 catch 回调中
/* e.g:
var deferred = $q.defer();
setTimeout(function(){
deferred.resolve('SUCCESS');
}, 1000);
deferred.promise.then(function(r){
return $q.reject('ERROR');
}).then(function(r){
console.log('success >>> ', r);
}).catch(function(r){
console.log('error >>> ', r);
});
*/

var reject = function(reason) {
var result = new Deferred();
result.reject(reason);
return result.promise;
};

// 同上 reject 执行 通过完成的回调
var resolve = function(value, callback, errback, progressBack) {
var result = new Deferred();
result.resolve(value);
return result.promise.then(callback, errback, progressBack);
};

// 最有意思的是 all 方法
// 巧妙的通过 resolve 方法 将 新创建的 内部的 deferred 的 $$resolve 和 $$reject 传给 循环中 promise 的 then 作为回调
// all 方法 内创建的 deferred 对象 控制着全局
// 计数器控制着所有的成功之后 执行 deferred.resolve(results)
// 当有一个失败则执行 deferred.reject(reason)
function all(promises) {
var deferred = new Deferred(),
// 对每个 promise 添加计数器
counter = 0,
results = isArray(promises) ? [] : {};

promises.forEach(function(promise, key) {
counter++;
resolve(promise).then(function(value) {
if (results.hasOwnProperty(key)) return;
results[key] = value;
if (!(--counter)) deferred.resolve(results);
}, function(reason) {
if (results.hasOwnProperty(key)) return;
deferred.reject(reason);
});
});

// 如果 promises 为空 直接 通过
if (counter === 0) {
deferred.resolve(results);
}

return deferred.promise;
}

// 改变函数调用 this 指向
function callOnce(self, resolveFn, rejectFn) {
var called = false;
function wrap(fn) {
return function(value) {
if (called) return;
called = true;
fn.call(self, value);
};
}
return [wrap(resolveFn), wrap(rejectFn)];
}

var makePromise = function makePromise(value, resolved) {
var result = new Deferred();
if (resolved) {
result.resolve(value);
} else {
result.reject(value);
}
return result.promise;
};

var handleCallback = function handleCallback(value, isResolved, callback) {
var callbackOutput = null;
if (isFunction(callback)) callbackOutput = callback();
if (isPromiseLike(callbackOutput)) {
return callbackOutput.then(function() {
return makePromise(value, isResolved);
}, function(error) {
return makePromise(error, false);
});
} else {
return makePromise(value, isResolved);
}
};


// 以下为 模拟方法
function isFunction(fn){ return typeof fn === 'function'; }
function isObject(obj){ return typeof obj === 'object'; }
function isArray(array){ return Array.isArray(array); }
function isPromiseLike(obj) { return obj && isFunction(obj.then); }
function extend(obj, _proto){
Object.keys(_proto).forEach(function(key){
obj[key] = _proto[key];
});
}

$q.defer = defer;
$q.reject = reject;
$q.resolve = resolve;
$q.all = all;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 每个 $q.defer()  实际 都会 new 一个 Deferred 对象
{ // Deferred 对象
// 在 构造 Deferred 对象的同时会 new 一个 Promise 对象
// 在 angular 看来只要有 then 方法的就是 Promise 对象
promise: { // Promise 对象
// 每个 Promise 对象都有一个 $$state
// 其中 status 记录 当前 Promise 对象的状态
// 一共四种状态: 该状态同时也对应于 pending 中的回调函数
// 0: 等待 初始状态
// 1: 通过 对应于 pending 中的 onFulfilled 回调
// 2: 拒绝 对应于 pending 中的 onRejected 回调
// -1: 处理传递的 promise 对象 deferred.resolve(promise)
// pending 会在 执行完 .then() 方法后动态添加上 用于存储: 成功、失败和 finally 的回调函数
// value 用于存储 结果值 并传递给回调函数
$$state: {
status: 0,
pending: [ // .then() 之后会添加回调函数
[_deferred, onFulfilled, onRejected, progressBack]
],
value: undefined, // deferred.resolve(value)
},
_proto_: {
// then: Promise 对象的核心方法
// 主要用于添加回调函数 和 执行回调(status > 0 时)
then: f(){},
catch: f(){},
finally: f(){}
}
},
resolve: f(){},
reject: f(){},
notify: f(){},
_proto_: {
resolve: f(){},
$$resolve:f(){},
reject: f(){},
$$reject: f(){},
notify: f(){}
}
}